package com.cloudfun.campusshare.configuration.config;

import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.cloudfun.campusshare.util.tencent.wechat.WeChatUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

@Slf4j
@Data
@Component
public class WxConfig {
    private final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
    private final String JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi";


    @Value("${wechat.official.appId}")
    private String appId;

    @Value("${wechat.official.secret}")
    private String secret;

    @Autowired
    private StringRedisTemplate redisTemplate;

    public String accessToken() {
        ValueOperations<String, String> redis = redisTemplate.opsForValue();
        String accessToken;
        if ((accessToken = redis.get("access_token")) == null) {
            HttpRequest request = HttpRequest.get(String.format(ACCESS_TOKEN_URL, appId, secret));
            accessToken = JSONUtil.parseObj(request.execute().body()).getStr("access_token");
            if(StringUtils.isNotBlank(accessToken)){
                redis.set("access_token", accessToken, 7200, TimeUnit.SECONDS);
            }
        }
        return accessToken;
    }

    public String ticket(String accessToken) {
        ValueOperations<String, String> redis = redisTemplate.opsForValue();
        String ticket;
        if ((ticket = redis.get("ticket")) == null) {
            HttpRequest request = HttpRequest.get(String.format(JSAPI_TICKET_URL, accessToken));
            ticket = JSONUtil.parseObj(request.execute().body()).getStr("ticket");
            redis.set("ticket", ticket, 7200, TimeUnit.SECONDS);
        }
        return ticket;
    }

    public Map<String, Object> sign(String url, String ticket) {
        Map<String, Object> map = new TreeMap();
        map.put("noncestr", WeChatUtil.genRandomStr());
        map.put("jsapi_ticket", ticket);
        map.put("timestamp", System.currentTimeMillis() / 1000);
        map.put("url", URLDecoder.decode(url));
        StringBuilder builder = new StringBuilder();
        map.forEach((k, v) -> {
            if (builder.length() <= 0) {
                builder.append(String.format("%s=%s", k, v));
            } else {
                builder.append(String.format("&%s=%s", k, v));
            }
        });
        map.put("signature", sha1(builder.toString()));
        log.info("sign:{}", builder.toString());
        map.put("appid", appId);
        return map;
    }

    public String sha1(String value) {
        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(value.getBytes("UTF-8"));
            return byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }
}
